package com.xingfly.web;

import com.xingfly.model.User;
import com.xingfly.security.jwt.model.JwtAuthRequest;
import com.xingfly.security.jwt.model.JwtAuthResponse;
import com.xingfly.security.jwt.model.JwtUser;
import com.xingfly.security.jwt.service.JwtUserDetailsService;
import com.xingfly.security.jwt.util.JwtConstants;
import com.xingfly.security.jwt.util.JwtTokenUtil;
import com.xingfly.service.AccountService;
import com.xingfly.service.JwtService;
import com.xingfly.web.model.ResponseModel;
import org.apache.catalina.servlet4preview.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.mobile.device.Device;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;

/**
 * Created by SuperS on 2016/12/21.
 */
@RestController
public class AuthController {
    //    @Value("${jwt.header}")
    private String tokenHeader = JwtConstants.JWT_TOKEN_HEADER_PARAM;
    @Autowired
    private AccountService accountService;
    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private JwtUserDetailsService jwtUserDetailsService;

    @Autowired
    private JwtService jwtService;

    @PostMapping("/auth")
    public ResponseModel<?> createAuthToken(@RequestBody JwtAuthRequest authRequest, Device device) {
        try {
            System.out.println(authRequest.getPassword());
            System.out.println(authRequest.getUsername());
            final Authentication authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            authRequest.getUsername(),
                            authRequest.getPassword()
                    )
            );
            SecurityContextHolder.getContext().setAuthentication(authentication);
            final UserDetails userDetails = jwtUserDetailsService.loadUserByUsername(authRequest.getUsername());
            User user = accountService.find(userDetails.getUsername());
            final String token = jwtTokenUtil.generateToken(userDetails, device);
            jwtService.save(user.getId(), token);
            return ResponseModel.ok(new JwtAuthResponse(token));
        } catch (Exception e) {
            return ResponseModel.error(HttpStatus.BAD_REQUEST, "用户名或密码错误");
        }
    }

    @PutMapping("/auth")
    public ResponseModel<?> refreshAndGetAuthToken(HttpServletRequest request) {
        String token = request.getHeader(tokenHeader);
        String username = jwtTokenUtil.getUsernameFromToken(token);
        JwtUser user = (JwtUser) jwtUserDetailsService.loadUserByUsername(username);
        if (jwtTokenUtil.canTokenBeRefreshed(token, user.getLastPasswordResetDate()) && jwtTokenUtil.validateToken(token, user) && jwtService.getToken(user.getId()).equals(token)) {
            String refreshedToken = jwtTokenUtil.refreshToken(token);
            jwtService.save(user.getId(), refreshedToken);
            return ResponseModel.ok(new JwtAuthResponse(refreshedToken));
        } else {
            return ResponseModel.create(null, HttpStatus.UNAUTHORIZED);
        }
    }

    @DeleteMapping("auth")
    public ResponseModel<?> deleteToken(HttpServletRequest request) {
        String token = request.getHeader(tokenHeader);
        String username = jwtTokenUtil.getUsernameFromToken(token);
        JwtUser user = (JwtUser) jwtUserDetailsService.loadUserByUsername(username);
        if (jwtService.getToken(user.getId()) == null) {
            return ResponseModel.error(HttpStatus.BAD_REQUEST, "用户未登录");
        }
        jwtService.delete(user.getId());
        return ResponseModel.create(null, HttpStatus.OK);
    }
}
